/*
alert tcp $EXTERNAL_NET $HTTP_PORTS -> $HOME_NET any (msg:"WEB-CLIENT Adobe Flash Player multimedia file DefineSceneAndFrameLabelData code execution attempt"; flowbits:isset,file.swf; flow:to_client,established; content:"FWS"; metadata:policy security-ips drop, service http; reference:cve,2007-0071; reference:bugtraq,28695; reference:url,www.adobe.com/support/security/bulletins/apsb08-11.html; classtype:attempted-user; sid:17647;)
 */
/*
 * Vuln Title: Adobe Flash Player Multimedia File DefineSceneAndFrameLabelData
 *             Code Execution
 *
 * Copyright (C) 2005-2010 Sourcefire, Inc. All Rights Reserved
 *
 * Written by Sojeong Hong, Sourcefire VRT <shong@sourcefire.com>
 *
 * Auto-generated by Sojeong Hong
 *
 * This file may contain proprietary rules that were created, tested and
 * certified by Sourcefire, Inc. (the "VRT Certified Rules") as well as
 * rules that were created by Sourcefire and other third parties and
 * distributed under the GNU General Public License (the "GPL Rules").  The
 * VRT Certified Rules contained in this file are the property of
 * Sourcefire, Inc. Copyright 2005 Sourcefire, Inc. All Rights Reserved.
 * The GPL Rules created by Sourcefire, Inc. are the property of
 * Sourcefire, Inc. Copyright 2002-2005 Sourcefire, Inc. All Rights
 * Reserved.  All other GPL Rules are owned and copyrighted by their
 * respective owners (please see www.snort.org/contributors for a list of
 * owners and their respective copyrights).  In order to determine what
 * rules are VRT Certified Rules or GPL Rules, please refer to the VRT
 * Certified Rules License Agreement.
 */

#include "sf_snort_plugin_api.h"
#include "sf_snort_packet.h"

#include "so-util.h"

#include <math.h>

//#define DEBUG
#ifdef DEBUG
#define DEBUG_SO(code) code
#else
#define DEBUG_SO(code)
#endif

/* declare detection functions */
int rule17647eval(void *p);

/* declare rule data structures */
/* flowbits:isset "file.swf"; */
static FlowBitsInfo rule17647flowbits0 =
{
    "file.swf",
    FLOWBIT_ISSET,
    0,
};

static RuleOption rule17647option0 =
{
    OPTION_TYPE_FLOWBIT,
    {
        &rule17647flowbits0
    }
};
/* flow:established, to_client; */
static FlowFlags rule17647flow1 = 
{
    FLOW_ESTABLISHED|FLOW_TO_CLIENT
};

static RuleOption rule17647option1 =
{
    OPTION_TYPE_FLOWFLAGS,
    {
        &rule17647flow1
    }
};

// content:"FWS", depth 0, fast_pattern; 
static ContentInfo rule17647content2 = 
{
    (uint8_t *) "FWS", /* pattern (now in snort content format) */
    3, /* depth */
    0, /* offset */
    CONTENT_FAST_PATTERN|CONTENT_BUF_NORMALIZED, /* flags */
    NULL, /* holder for boyer/moore PTR */
    NULL, /* more holder info - byteform */
    0, /* byteform length */
    0 /* increment length*/
};

static RuleOption rule17647option2 = 
{
    OPTION_TYPE_CONTENT,
    {
        &rule17647content2
    }
};

// file_data;
static CursorInfo rule17647file_data3 =
{
    0, /* offset */
    CONTENT_BUF_NORMALIZED /* flags */
};

static RuleOption rule17647option3 =
{
#ifndef MISSINGFILEDATA
    OPTION_TYPE_FILE_DATA,
#else
    OPTION_TYPE_SET_CURSOR,
#endif
    {
        &rule17647file_data3
    }
};

/* references for sid 17647 */
/* reference: bugtraq "28695"; */
static RuleReference rule17647ref1 = 
{
    "bugtraq", /* type */
    "28695" /* value */
};

/* reference: cve "2007-0071"; */
static RuleReference rule17647ref2 = 
{
    "cve", /* type */
    "2007-0071" /* value */
};

/* reference: url "www.adobe.com/support/security/bulletins/apsb08-11.html"; */
static RuleReference rule17647ref3 = 
{
    "url", /* type */
    "www.adobe.com/support/security/bulletins/apsb08-11.html" /* value */
};

static RuleReference *rule17647refs[] =
{
    &rule17647ref1,
    &rule17647ref2,
    &rule17647ref3,
    NULL
};

/* metadata for sid 17647 */
/* metadata:service http, policy security-ips drop; */
static RuleMetaData rule17647service1 = 
{
    "service http"
};


static RuleMetaData rule17647policy1 = 
{
    "policy security-ips drop"
};

static RuleMetaData rule17647policy2 =
{
   "policy max-detect-ips drop"
};

static RuleMetaData *rule17647metadata[] =
{
    &rule17647service1,
    &rule17647policy1,
    &rule17647policy2,
    NULL
};

RuleOption *rule17647options[] =
{
    &rule17647option0,
    &rule17647option1,
    &rule17647option2,
    &rule17647option3,
    NULL
};

Rule rule17647 = {
   /* rule header, akin to => tcp any any -> any any */
   {
       IPPROTO_TCP, /* proto */
       "$EXTERNAL_NET", /* SRCIP     */
       "$HTTP_PORTS", /* SRCPORT   */
       0, /* DIRECTION */
       "$HOME_NET", /* DSTIP     */
       "any", /* DSTPORT   */
   },
   /* metadata */
   { 
       3,  /* genid */
       17647, /* sigid */
       8, /* revision */
       "attempted-user", /* classification */
       0,  /* hardcoded priority XXX NOT PROVIDED BY GRAMMAR YET! */
       "FILE-FLASH Adobe Flash Player multimedia file DefineSceneAndFrameLabelData code execution attempt",     /* message */
       rule17647refs /* ptr to references */
       ,rule17647metadata
   },
   rule17647options, /* ptr to rule options */
   &rule17647eval, /* DO NOT use the built in detection function */
   0 /* am I initialized yet? */
};


/* detection functions */
int rule17647eval(void *p) {
    const uint8_t *cursor_normal = 0, *end_of_payload;
    SFSnortPacket *sp = (SFSnortPacket *) p;
    const uint8_t *ov_check = 0;

    uint8_t  Nbits;
    uint16_t rect_size;
    uint16_t type_and_length;
    uint16_t tag_type;
    uint32_t tag_length; 

    DEBUG_SO(printf("rule17647eval enter\n");)

    if(sp == NULL)
        return RULE_NOMATCH;

    // flowbits:isset "file.swf";
    if (processFlowbits(p, rule17647options[0]->option_u.flowBit) <= 0)
        return RULE_NOMATCH;
    
    // flow:established, to_client;
    if (checkFlow(p, rule17647options[1]->option_u.flowFlags) <= 0 )
        return RULE_NOMATCH;

    // file_data;
    #ifndef MISSINGFILEDATA
    if (fileData(p, rule17647options[3]->option_u.cursor, &cursor_normal) <= 0) {
    #else
    if (setCursor(p, rule17647options[3]->option_u.cursor, &cursor_normal) <= 0) {
    #endif
        return RULE_NOMATCH;
    }

    if(getBuffer(sp, CONTENT_BUF_NORMALIZED, &cursor_normal, &end_of_payload) <= 0)
        return RULE_NOMATCH;
    
    // content:"FWS", depth 0, fast_pattern;    
    if (contentMatch(p, rule17647options[2]->option_u.content, &cursor_normal) > 0)
    {
        /*
         * skip over the variable size SWF header
         */
        if (cursor_normal + 15 > end_of_payload) // 15 = minimum header size + minimum record header size
            return RULE_NOMATCH;
        
        // skip Version (UI8) and FileLength (UI32)
        cursor_normal += 5;                 

        // calculate FrameSize (RECT) size
        Nbits = (*cursor_normal & 0xF8) >> 3;                        // read left most 5 bits
        rect_size = (uint16_t)ceil((double)(5 + (Nbits * 4))/8) ;   // total in bytes
        DEBUG_SO(printf("rect_size [%d]\n", rect_size);)
        
        // skip FrameSize (RECT), FrameRate (UI16), and FrameCount (U16)
        ov_check = cursor_normal + rect_size + 4;
        if(ov_check < cursor_normal) 
           return RULE_NOMATCH;

        cursor_normal += rect_size + 4;

        /* 
         * loop through all tags
         */
        
        while (cursor_normal + 7 <= end_of_payload)
        {
            type_and_length = read_little_16(cursor_normal);
            cursor_normal += 2;

            // tag length can be stored in a short or a long format
            tag_type   = (type_and_length & 0xFFC0) >> 6;                                        
            tag_length = type_and_length & 0x003F;

            if (tag_length == 0x3F) // tag length is in the long format
            {                        
                tag_length = read_little_32(cursor_normal);
                cursor_normal += 4;
                               
                if (cursor_normal + 5 > end_of_payload) 
                    return RULE_NOMATCH;                
            }

            DEBUG_SO(printf("tag_type   [%d]\n", tag_type);)
            DEBUG_SO(printf("tag_length [%d]\n", tag_length);)                    

            // once DefineSceneAndFrameLabelData record is met, do futher inspection
            if (tag_type == 0x56) 
            {                
                // malicious condition
                if ((*cursor_normal & 0x80) && (*(cursor_normal+1) & 0x80) && (*(cursor_normal+2) & 0x80)
                    && (*(cursor_normal+3) & 0x80) && (*(cursor_normal+4) & 0x08))
                {                   
                    DEBUG_SO(printf("SceneCount = %x%x%x%x%x\n", *cursor_normal, *(cursor_normal+1), *(cursor_normal+2), *(cursor_normal+3), *(cursor_normal+4));)
                    return RULE_MATCH;
                }
            }

            // integer overflow check
            ov_check = cursor_normal + tag_length;
            if(ov_check < cursor_normal) 
                return RULE_NOMATCH;
                
            cursor_normal += tag_length;            
        }        
    }
    
    return RULE_NOMATCH;
}
/*
Rule *rules[] = {
    &rule17647,
    NULL
};
*/
